/*
100,000,000（1亿）个浮点数求取平方根后的sin值(sin(sqrt(x))), as fast as you can。

1） 简单起见，就从1开始到100,000,000依次填充到输入。
2） 请使用你所知道的所有手段（什么多进程，多线程，内存映射，甚至网络集群，能用上的都用上）在最短的时间完成计算，将计算结果填充到内存。
3） 请记录从程序开始到100,000,000个结果填充到内存所消耗的时间，精确到ms。
4） 最后将结果写入磁盘，每行一个，保留3位小数，用以检查程序的正确性，结果写入磁盘的时间不计算。
*/

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>

#include <pthread.h>
#include<unistd.h>

const int numv = 100000000;
int numThread = 20;

struct ctinfo
{
	float* pdata;
	int offset;
	int cptnum;
};

int singleProcessSingleThread(float * outdata)
{	
	for(int cpt = 1; cpt<= numv; ++cpt)
	{
		outdata[cpt-1] = sin(sqrt(cpt));	
	}
	return 0;
}

void * computeThread(void* pcptinf)
{
	if(NULL == pcptinf)
	{
		return 0;
	}
	struct ctinfo * thectinfo = (struct ctinfo *)pcptinf;
	float* outdata = thectinfo->pdata;
	for(int k=0;k<thectinfo->cptnum;++k)
	{
		outdata[k] = sin(sqrt(k + thectinfo->offset + 1));
	}
	return 0;
}

int multiThread(float * outdata)
{
	pthread_t tidp[numThread];
	struct ctinfo cptinf[numThread];
	int cptnum = (numv/numThread);

	for(int i=0;i<numThread;++i)
	{
		cptinf[i].cptnum = cptnum;
		cptinf[i].offset = i * cptnum;
		cptinf[i].pdata = outdata + (i * cptnum);

		//printf("in multiThread pthread_create %d %d %d\n", i, cptinf[i].offset, cptinf[i].cptnum);
		int error = pthread_create(&(tidp[i]),NULL, computeThread, (void*)(&(cptinf[i])));
		if(0 != error)
		{
			printf("in multiThread fail to call pthread_create\n");
			return 0;
		}
	}
	void* re;
	for(int i=0;i<numThread;++i)
	{
		//printf("in multiThread pthread_join %d\n", i);
		pthread_join(tidp[i], &re);
	}
	return 0;
}

int main()
{
	numThread = sysconf(_SC_NPROCESSORS_CONF);
	timeval clkBegin;
	gettimeofday(&clkBegin, NULL);
	//clock_t clkBegin = clock();

	float * outdata  = (float*) malloc(sizeof(float) * numv);
	timeval clkMalloc;
	gettimeofday(&clkMalloc, NULL);
	//clock_t clkMalloc = clock();

	//singleProcessSingleThread(outdata);
	multiThread(outdata);

	timeval clkEnd;
	gettimeofday(&clkEnd, NULL);
	//clock_t clkEnd = clock();

	// 打印时间信息
	long timemalcusec = (clkMalloc.tv_usec - clkBegin.tv_usec);
	long timecostusec = (clkEnd.tv_usec - clkBegin.tv_usec);
	timecostusec += 1000000L*(clkEnd.tv_sec - clkBegin.tv_sec);

	long timecostMs = timecostusec/1000L;
	//printf("malloc time: %d clock\n", (clkMalloc-clkBegin));
	//printf("compute time: %d clock\n", timecost);
	printf("numThread = %d\n", numThread);
	printf("malloc time: %ld us\n", timemalcusec);
	printf("compute time: %ld us\n", timecostusec);
	printf("compute time: %ld ms\n", timecostMs);
	
	// 计算结果写入磁盘
	FILE* cpref = fopen("cpre.data", "w");
	for(int cpt = 1; cpt<= numv; ++cpt)
	{
		fprintf(cpref, "%.3f\n", outdata[cpt-1]);	
		break;
	}

	fclose(cpref);
	free(outdata);
	return 0;
}
